package top.lingkang.finaloauth2.server.config;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import top.lingkang.finaloauth2.server.auth.AuthDetailsService;
import top.lingkang.finaloauth2.server.auth.AuthServerGetToken;
import top.lingkang.finaloauth2.server.auth.AuthServerResponse;
import top.lingkang.finaloauth2.server.auth.AuthorizationMode;
import top.lingkang.finaloauth2.server.auth.impl.AuthorizationModeManage;
import top.lingkang.finaloauth2.server.auth.impl.DefaultAuthDetailsService;
import top.lingkang.finaloauth2.server.auth.impl.DefaultAuthServerGetToken;
import top.lingkang.finaloauth2.server.auth.impl.DefaultAuthServerResponse;
import top.lingkang.finaloauth2.server.base.AuthKeyGenerate;
import top.lingkang.finaloauth2.server.base.impl.DefaultAuthKeyGenerate;
import top.lingkang.finaloauth2.server.client.ClientDetailsService;
import top.lingkang.finaloauth2.server.client.ClientDetailsServiceBuilder;
import top.lingkang.finaloauth2.server.client.impl.InMemoryClientDetailsService;
import top.lingkang.finaloauth2.server.client.impl.JdbcClientDetailsService;
import top.lingkang.finaloauth2.server.controller.AuthServerController;
import top.lingkang.finaloauth2.server.error.AuthServerExceptionHandler;
import top.lingkang.finaloauth2.server.error.DefaultAuthServerExceptionHandler;
import top.lingkang.finaloauth2.server.error.ServerException;
import top.lingkang.finaloauth2.server.store.TokenStore;
import top.lingkang.finaloauth2.server.store.impl.InMemoryTokenStore;

import javax.annotation.PostConstruct;

/**
 * @author lingkang
 * Created by 2022/3/16
 */
@Import({AuthServerController.class})
public class AuthorizationServerConfiguration {
    private static final Log log = LogFactory.getLog(AuthorizationServerConfiguration.class);
    private AuthorizationServerProperties authorizationServerProperties = new AuthorizationServerProperties();
    private ClientDetailsServiceBuilder clientDetailsServiceBuilder = new ClientDetailsServiceBuilder();
    @Value("${spring.main.allow-bean-definition-overriding:false}")
    private boolean overriding;

    protected void config(AuthorizationServerProperties config) {

    }

    protected void configClient(ClientDetailsServiceBuilder clients) {

    }

    @PostConstruct
    private void init() {
        config(authorizationServerProperties);
        if (authorizationServerProperties.getTokenMaxExpires() > authorizationServerProperties.getRefreshTokenMaxExpires()) {
            throw new ServerException("server: token 最大失效时间不能大于 refreshToken最大时间！");
        }

        configClient(clientDetailsServiceBuilder);
        if (clientDetailsServiceBuilder.getDataSource() == null && clientDetailsServiceBuilder.getMemory() == null) {
            log.warn("server: 未配置数据库读取授权客户端，使用默认授权客户端配置");
            // 默认值
            clientDetailsServiceBuilder.inMemory()
                    .addClient("client_id")
                    .secret("secret")
                    .authorizedGrantTypes("password", "refresh_token", "code")
                    .scope("all");
            log.info("server: 未配置授权客户端，默认授权客户端配置：" + clientDetailsServiceBuilder.getMemory().get("client_id"));
        }

        if (!overriding) {
            log.warn("server: 未开启bean同名重写，无法使用final-oauth2重写定制：spring.main.allow-bean-definition-overriding=true");
        }
        log.info("server: AuthorizationServer init finish!");
    }

    @Bean
    public AuthorizationServerProperties authorizationServerProperties() {
        return authorizationServerProperties;
    }

    @Bean
    public AuthorizationMode authorizationMode() {
        return new AuthorizationModeManage();
    }

    // ----------------------- 下面是可定制bean ------------------------------------

    @Bean
    @ConditionalOnMissingBean
    public AuthServerResponse authServerResponse() {
        return new DefaultAuthServerResponse();
    }

    @Bean
    @ConditionalOnMissingBean
    public ClientDetailsService clientDetailsService() {
        if (clientDetailsServiceBuilder.getDataSource() != null && clientDetailsServiceBuilder.getMemory() != null) {
            log.warn("server: 同时使用jdbc数据库和内存存储授权客户端信息，将会只选择数据库作为客户端数据存储！");
            return new JdbcClientDetailsService(clientDetailsServiceBuilder.getDataSource());
        }
        if (clientDetailsServiceBuilder.getMemory() != null) {
            return new InMemoryClientDetailsService(clientDetailsServiceBuilder.getMemory());
        }
        return new JdbcClientDetailsService(clientDetailsServiceBuilder.getDataSource());
    }

    @Bean
    @ConditionalOnMissingBean
    public TokenStore tokenStore() {
        if (authorizationServerProperties.getTokenStore() != null) {
            return authorizationServerProperties.getTokenStore();
        }
        return new InMemoryTokenStore();
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthServerExceptionHandler authServerExceptionHandler() {
        if (authorizationServerProperties.getAuthServerExceptionHandler() != null)
            return authorizationServerProperties.getAuthServerExceptionHandler();
        return new DefaultAuthServerExceptionHandler();
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthDetailsService userDetailsService() {
        log.warn("server: 未注入AuthDetailsService自定义bean，使用默认的DefaultAuthDetailsService实现账号密码校验：final/final");
        return new DefaultAuthDetailsService();
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthKeyGenerate authKeyGenerate() {
        return new DefaultAuthKeyGenerate();
    }

    @Bean
    @ConditionalOnMissingBean
    public AuthServerGetToken authServerGetToken() {
        return new DefaultAuthServerGetToken();
    }
}
